#include "precompile.h"

#include <vsys>

#include "UROptimize.h"
#include "Storage.h"

template <class T>
OptItemDataArray<T>::OptItemDataArray()
{
	m_pDataArray = NULL;
	m_nSize = 0;
	m_nMemSize = 0;
}

template <class T>
OptItemDataArray<T>::~OptItemDataArray()
{
	clear();
}

template <class T>
void OptItemDataArray<T>::clear()
{
	if (m_pDataArray != NULL)
		delete []m_pDataArray;

	m_pDataArray = NULL;
	m_nSize = 0;
	m_nMemSize = 0;
}

template <class T>
int32 OptItemDataArray<T>::GetSize()const
{
	return m_nSize;
};

template <class T>
T& OptItemDataArray<T>::GetAt(int32 nIndex)const
{
	return m_pDataArray[m_pDataArray[nIndex].m_nIndexData].m_Data;
}

template <class T>
bool OptItemDataArray<T>::Find(objectid oid, int32& nSortIndex)const
{
	if(m_pDataArray==NULL || m_nSize<=0)
	{
		nSortIndex = 0;
		return false;
	}
	else if(oid > m_pDataArray[m_pDataArray[m_nSize-1].m_nIndexData].m_Data.m_oid)
	{
		nSortIndex = m_nSize;
		return false;
	}
	else if(oid < m_pDataArray[m_pDataArray[0].m_nIndexData].m_Data.m_oid)
	{
		nSortIndex = 0;
		return false;
	}
	return Find(oid, nSortIndex, 0, m_nSize-1);
}

template <class T>
bool OptItemDataArray<T>::Find(objectid oid, int32& nSortIndex, int32 nBegin, int32 nEnd)const
{
	int32 nMid = (nBegin+nEnd)/2;
	objectid oidMidPos = m_pDataArray[m_pDataArray[nMid].m_nIndexData].m_Data.m_oid;
	if(oidMidPos == oid)
	{
		nSortIndex = nMid;
		return true;
	}
	else if(oid < oidMidPos)
	{
		nSortIndex = nBegin;
		if(nBegin > nMid-1)
			return false;
		return Find(oid, nSortIndex, nBegin, nMid-1);
	}
	nSortIndex = nMid+1;
	if(nMid+1 > nEnd)
		return false;
	return Find(oid, nSortIndex, nMid+1, nEnd);
}

template <class T>
bool OptItemDataArray<T>::InsertAt(const T& Item, int32 nPos)
{
	if(nPos<0 || nPos>m_nSize)
		return false;
	if(m_nMemSize <= m_nSize)
	{
		OptItemData* pDataArray = new OptItemData[m_nMemSize+MenAllocSize];
		if(pDataArray == NULL)
			return false;
		memmove(pDataArray, m_pDataArray, m_nMemSize * sizeof(OptItemData));
		delete []m_pDataArray;
		m_pDataArray = pDataArray;
		m_nMemSize += MenAllocSize;
		for(int32 i=m_nSize; i<m_nMemSize; i++)
		{
			m_pDataArray[i].m_nIndexData = i;
		}
	}
	int32 nLastIndexData = m_pDataArray[m_nSize].m_nIndexData;
	for(int32 i=m_nSize; i>nPos; i--)
	{
		m_pDataArray[i].m_nIndexData = m_pDataArray[i-1].m_nIndexData;
	}
	m_pDataArray[nPos].m_nIndexData = nLastIndexData;
	m_pDataArray[nLastIndexData].m_Data = Item;
	m_nSize++;
	return true;
}

template <class T>
bool OptItemDataArray<T>::RemoveAt(int32 nIndex)
{
	if(nIndex < 0)
		return false;
	if(nIndex >= m_nSize)
		return false;
	int32 nIndexIndexData = m_pDataArray[nIndex].m_nIndexData;
	for(int32 i=nIndex; i<m_nSize-1; i++)
	{
		m_pDataArray[i].m_nIndexData = m_pDataArray[i+1].m_nIndexData;
	}
	m_pDataArray[m_nSize-1].m_nIndexData = nIndexIndexData;
	m_nSize--;
	return true;
}



UROptimize::UROptimize()
{
	m_nItemSize=0;
	for(int32 i=0; i<UROptimizeSize; i++)
	{
		m_nMapSize[i] = 0;
	}
	m_nLastFindPos = -1;
}

UROptimize::~UROptimize()
{
	Clear();
}

int32 UROptimize::AppendItem(const UROptItem& optItem,IFileStream* pIFStream)
{
	int32 nMapPos = optItem.m_oid%UROptimizeSize;
	int32 nPos = 0;
	if (optItem.m_kState==kAdd)
	{
		bool bFindItem = m_MatrixOptItemMap[nMapPos].Find(optItem.m_oid, nPos);
		ASSERT(!bFindItem);
		m_MatrixOptItemMap[nMapPos].InsertAt(optItem,nPos);
		m_nMapSize[nMapPos]++;
		m_nItemSize++;

		m_LastOptItem = optItem;
		m_nLastFindPos = nPos;
		return nPos;
	}	

	bool bFind = false;
	if((m_nLastFindPos>=0)&&(m_LastOptItem.m_oid==optItem.m_oid))
	{
		bFind = true;
		nPos = m_nLastFindPos;
	}
	if(!bFind)
		bFind = m_MatrixOptItemMap[nMapPos].Find(optItem.m_oid, nPos);
	if(!bFind)
	{
		m_MatrixOptItemMap[nMapPos].InsertAt(optItem,nPos);
		m_nMapSize[nMapPos]++;
		m_nItemSize++;

		m_LastOptItem = optItem;
		m_nLastFindPos = nPos;
		return nPos;
	}

	const UROptItem& optFindItem = m_MatrixOptItemMap[nMapPos].GetAt(nPos);
	if (optFindItem.m_kState==kAdd&&optItem.m_kState==kDelete)
	{
		if(pIFStream!=NULL)
		{
			unsigned long lCurPos=pIFStream->GetCurrentPos();
			pIFStream->Seek(IFileStream::kBegin,optFindItem.m_lBeginPos);
			ulong lOffset;
//			lOffset=optFindItem.m_lEndPos-optFindItem.m_lBeginPos;
			lOffset = optFindItem.GetOffset();
			gtl::ArchiveTypeInOutOperator<ulong>::Save(pIFStream,0x7fffffff&lOffset);
			pIFStream->Seek(IFileStream::kBegin,lCurPos);
		}
		m_MatrixOptItemMap[nMapPos].RemoveAt(nPos);
		m_nMapSize[nMapPos]--;
		m_nItemSize--;
		m_LastOptItem = UROptItem();
		m_nLastFindPos = -1;
	}
	else if (optItem.m_kState==kDelete&&optFindItem.m_kState==kModify)
	{
		if(pIFStream!=NULL)
		{
			unsigned long lCurPos=pIFStream->GetCurrentPos();
			pIFStream->Seek(IFileStream::kBegin,optFindItem.m_lBeginPos+sizeof(objectid));
			gtl::ArchiveTypeInOutOperator<byte>::Save(pIFStream,byte(0x82));
			pIFStream->Seek(IFileStream::kBegin,lCurPos);
		}
		m_MatrixOptItemMap[nMapPos].GetAt(nPos).m_kState = kDelete;

		m_LastOptItem = optItem;
		m_nLastFindPos = nPos;
	}
	return -1;
}

void UROptimize::Clear()
{
	m_nItemSize=0;
	for(int32 i=0; i<UROptimizeSize; i++)
	{
		if(m_nMapSize[i] > 0)
		{
			m_MatrixOptItemMap[i].clear();
			m_nMapSize[i] = 0;
		}
	}
	m_nLastFindPos = -1;
}

void UROptimize::EnumItems(EnumURItemsCallBack* pFunc)const
{
	if(pFunc == NULL)
		return;

	for(int32 i=0; i < UROptimizeSize; i++)
	{
		for(int32 j=0;j<m_nMapSize[i];j++)
		{
			(*pFunc)(GetNthItem(i,j));
		}
	}
}

IncOptimize::IncOptimize()
{
	m_nItemSize=0;
	for(int32 i=0; i<UROptimizeSize; i++)
	{
		m_nMapSize[i] = 0;
	}
	m_nLastFindPos = -1;
}

IncOptimize::~IncOptimize()
{
	Clear();
}


int32 IncOptimize::InsertItem(const OpItem& optItem)
{
	int32 nMapPos = optItem.m_oid%UROptimizeSize;
	int32 nPos = 0;

	m_MatrixOptItemMap[nMapPos].Find(optItem.m_oid, nPos);
	m_MatrixOptItemMap[nMapPos].InsertAt(optItem,nPos);
	m_nMapSize[nMapPos]++;
	m_nItemSize++;

	m_LastOptItem = optItem;
	m_nLastFindPos = nPos;
	return nPos;
}

int32 IncOptimize::AppendItem(const OpItem& optItem)
{
	int32 nMapPos = optItem.m_oid%UROptimizeSize;
	int32 nPos = 0;
	if (optItem.m_kState==kAdd)
	{
		if (m_MatrixOptItemMap[nMapPos].Find(optItem.m_oid, nPos))
		{
			m_MatrixOptItemMap[nMapPos].GetAt(nPos).m_kState = kAdd;
			m_MatrixOptItemMap[nMapPos].GetAt(nPos).m_bNeedDel=true;
			m_LastOptItem = optItem;
			m_nLastFindPos = nPos;
			return -1;
		}
		else
		{
			m_MatrixOptItemMap[nMapPos].InsertAt(optItem,nPos);
			m_nMapSize[nMapPos]++;
			m_nItemSize++;

			m_LastOptItem = optItem;
			m_nLastFindPos = nPos;
			return nPos;
		}
	}	

	bool bFind = false;
	if((m_nLastFindPos>=0)&&(m_LastOptItem.m_oid==optItem.m_oid))
	{
		bFind = true;
		nPos = m_nLastFindPos;
	}
	if(!bFind)
		bFind = m_MatrixOptItemMap[nMapPos].Find(optItem.m_oid, nPos);
	if(!bFind)
	{
		m_MatrixOptItemMap[nMapPos].InsertAt(optItem,nPos);
		m_nMapSize[nMapPos]++;
		m_nItemSize++;

		m_LastOptItem = optItem;
		m_nLastFindPos = nPos;
		return nPos;
	}

	const OpItem& optFindItem = m_MatrixOptItemMap[nMapPos].GetAt(nPos);
	if (optFindItem.m_kState==kAdd&&optItem.m_kState==kDelete)
	{
		if(optFindItem.m_bNeedDel==true)
		{
			m_MatrixOptItemMap[nMapPos].GetAt(nPos).m_kState = kDelete;
			m_LastOptItem = optItem;
			m_nLastFindPos = nPos;
			return -1;
		}
		else
		{
			m_MatrixOptItemMap[nMapPos].RemoveAt(nPos);
			m_nMapSize[nMapPos]--;
			m_nItemSize--;
			m_LastOptItem = OpItem();
			m_nLastFindPos = -1;
		}
	}
	else if (optItem.m_kState==kDelete&&optFindItem.m_kState==kModify)
	{
		m_MatrixOptItemMap[nMapPos].GetAt(nPos).m_kState = kDelete;

		m_LastOptItem = optItem;
		m_nLastFindPos = nPos;
	}
	return -1;
}

void IncOptimize::Clear()
{
	m_nItemSize=0;
	for(int32 i=0; i<UROptimizeSize; i++)
	{
		if(m_nMapSize[i] > 0)
		{
			m_MatrixOptItemMap[i].clear();
			m_nMapSize[i] = 0;
		}
	}
	m_nLastFindPos = -1;
}

void IncOptimize::EnumItems(EnumIncItemsCallBack* pFunc)const
{
	if(pFunc == NULL)
		return;

	for(int32 i=0; i < UROptimizeSize; i++)
	{
		for(int32 j=0;j<m_nMapSize[i];j++)
		{
			(*pFunc)(GetNthItem(i,j));
		}
	}
}